﻿
#region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;

#endregion

namespace MarketPulse.BusinessLogic.Private.StateMachine
{
    [Serializable]
    internal class VisitStateContext : IVisitStateContext
    {
        /// <summary>Property that stores the name of the class.</summary>
        private static readonly Type mClass = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;

        private IVisitState mState;

        private Visit mVisit;

        protected bool mThrowIfInvalid;

        internal VisitStateContext(Guid initialVisitStateGUID, Visit visit, bool throwIfInvalid)
        {
            mState = VisitStateFactory.Create(initialVisitStateGUID, throwIfInvalid);
            mVisit = visit;
            mThrowIfInvalid = throwIfInvalid;
        }

        public void SetState(IVisitState visitState)
        {
            mState = visitState;
            mVisit.VisitStatusTypeGUID = mState.StateGuid;
        }

        public IVisitState GetState()
        {
            return mState;
        }

        public bool CanTransition(string eventName)
        {
            MethodInfo methodInfo = mClass.GetMethod(eventName);
            
            if (methodInfo == null)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("Unknown event: [ ");
                sb.Append(eventName);
                sb.Append(" ] !");
                throw new ArgumentException(sb.ToString());
            }

            ParameterInfo[] paramInfo = methodInfo.GetParameters();
            object[] args = new object[paramInfo.Length];
            args[0] = true;
            for (ushort i = 1; i < paramInfo.Length; ++i)
            {
                args[i] = null;
            }

            return (bool)mClass.InvokeMember(eventName, 
                                                BindingFlags.Public
                                                | BindingFlags.InvokeMethod
                                                | BindingFlags.IgnoreCase
                                                | BindingFlags.Instance, 
                                                null, this, args);
        }

        public bool Assign(bool tryTransition, Guid userGuid, DateTime plannedDateTime)
        {
            return mState.Assign(this, tryTransition, userGuid, plannedDateTime);
        }

        public bool Unassign(bool tryTransition, Visit.PaymentStatus payment)
        {
            return mState.Unassign(this, tryTransition, payment);
        }

        public bool Release(bool tryTransition)
        {
            return mState.Release(this, tryTransition);
        }

        public bool StartDataEntry(bool tryTransition)
        {
            return mState.StartDataEntry(this, tryTransition);
        }

        public bool DataEnter(bool tryTransition, System.Xml.Linq.XElement responses)
        {
            return mState.DataEnter(this, tryTransition, responses);
        }

        public bool CompleteDataEntry(bool tryTransition)
        {
            return mState.CompleteDataEntry(this, tryTransition);
        }

        public bool QAStartDataEntry(bool tryTransition)
        {
            return mState.QAStartDataEntry(this, tryTransition);
        }

        public bool QADataEnter(bool tryTransition)
        {
            return mState.QADataEnter(this, tryTransition);
        }

        public bool QAApprove(bool tryTransition)
        {
            return mState.QAApprove(this, tryTransition);
        }

        public bool QAFail(bool tryTransition)
        {
            return mState.QAFail(this, tryTransition);
        }

        public bool QAPutOnHold(bool tryTransition)
        {
            return mState.QAPutOnHold(this, tryTransition);
        }

        public bool QAReopen(bool tryTransition)
        {
            return mState.QAReopen(this, tryTransition);
        }

        public bool MarkReadyForTransfer(bool tryTransition)
        {
            return mState.MarkReadyForTransfer(this, tryTransition);
        }

        public bool Revisit(bool tryTransition)
        {
            return mState.Revisit(this, tryTransition);
        }

    }
}
